﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Utility;
using System.Xml;

namespace SemAnalysis
{
    /// <summary>
    /// 语义分析
    /// </summary>
    public class SemAnalysis:ISemAnalysis.ISemAnalysis
    {
        //语法分析
        private static ISynAnalysis.ISynAnalysis _syn;
        //中间代码
        private readonly XmlDocument _recipe = new XmlDocument();
        //食谱名称
        private static string _name;
        //是否生成库文件
        private readonly bool _isForLib;

        /// <summary>
        /// 初始化
        /// </summary>
        public SemAnalysis(string code,bool isForLib, string recipeName)
        {
            _isForLib = isForLib;
            _syn = new SynAnalysis.SynAnalysis(code, isForLib);
            _name = recipeName.Remove(recipeName.LastIndexOf('.'));
            _recipe.LoadXml(String.Format("<?xml version=\"1.0\"?><recipe name=\"{0}\" version=\"1.0.2012.3\"></recipe>", _name));
        }

        /// <summary>
        /// 生成菜谱中间代码
        /// </summary>
        public void GetRecipe(string path)
        {
            if(_syn.Success())
            {
                TokenTable tokenTable = _syn.GetTokenTable();
                //TODO 包含库文件的处理
                //原料
                Ingredients(tokenTable.Ingredients);
                //自定义函数
                CookingFunctions(tokenTable.CookingFunctions);
                //主体部分
                Cooking(tokenTable.CookingCommands);
                //TODO 加密处理
                //保存文件
                if (_isForLib)
                {
                    _recipe.Save(path + _name + ".lib");
                }
                else
                {
                    _recipe.Save(path + _name + ".rcp");
                }
            }
        }

        /// <summary>
        /// 获取库文件代码
        /// </summary>
        public void GetLib()
        {
            //TODO
        }

        /// <summary>
        /// 是否成功
        /// </summary>
        /// <returns></returns>
        public bool Success()
        {
            return _syn.Success();
        }

        //原料转换
        private void Ingredients(IEnumerable<Ingredient> ingredients)
        {
            //创建“食材”标签
            XmlElement ings = _recipe.CreateElement("ingredients");
            //为“食材”标签中添加各种食材的说明
            foreach(Ingredient ingredient in ingredients)
            {
                //TODO 食材标准名称是否符合的判别
                XmlElement ing = _recipe.CreateElement("ingredient");
                ing.SetAttribute("name", ingredient.Name);
                ing.SetAttribute("amount", ingredient.Amount.ToString());
                ing.SetAttribute("dimension", ingredient.Dimension == Dimension.g ? "g" : "ml");
                ings.AppendChild(ing);
            }
            //将“食材”标签添加到XML文档中
            _recipe.GetElementsByTagName("recipe")[0].AppendChild(ings);
        }

        //自定义函数的转换
        private void CookingFunctions(IEnumerable<CookingFunction> cookingFunctions)
        {
            XmlElement funcs = _recipe.CreateElement("functions");
            foreach(CookingFunction cookingFunction in cookingFunctions)
            {
                XmlElement func = _recipe.CreateElement("function");
                func.SetAttribute("name", cookingFunction.Name);
                //参数
                XmlElement args = _recipe.CreateElement("arguments");
                foreach(Variable arg in cookingFunction.Arguments)
                {
                    XmlElement argName = _recipe.CreateElement("argument");
                    argName.SetAttribute("name", arg.Name);
                    args.AppendChild(argName);
                }
                func.AppendChild(args);
                //函数体
                XmlElement cmds = _recipe.CreateElement("commands");
                foreach (CookingCommand cookingCommand in cookingFunction.CookingCommands)
                {
                    XmlElement cmd = _recipe.CreateElement("command");
                    cmd.SetAttribute("name", cookingCommand.Name);
                    foreach (Argument arg in cookingCommand.Arguments)
                    {
                        XmlElement argValue = _recipe.CreateElement("argument");
                        argValue.SetAttribute("value",
                                              arg.Type == ArgumentType.Double
                                                  ? arg.DoubleValue.ToString()
                                                  : arg.VariableValue.Value.ToString());
                        cmd.AppendChild(argValue);
                    }
                    cmds.AppendChild(cmd);
                }
                func.AppendChild(cmds);
                funcs.AppendChild(func);
            }
            _recipe.GetElementsByTagName("recipe")[0].AppendChild(funcs);
        }

        //主体部分
        private void Cooking(IEnumerable<CookingCommand> cookingCommands)
        {
            XmlElement cooking = _recipe.CreateElement("cooking");
            foreach (CookingCommand cookingCommand in cookingCommands)
            {
                XmlElement cmd = _recipe.CreateElement("command");
                cmd.SetAttribute("name", cookingCommand.Name);
                foreach (Argument arg in cookingCommand.Arguments)
                {
                    XmlElement argValue = _recipe.CreateElement("argument");
                    argValue.SetAttribute("value",
                                          arg.Type == ArgumentType.Double
                                              ? arg.DoubleValue.ToString()
                                              : arg.VariableValue.Name);
                    cmd.AppendChild(argValue);
                }
                cooking.AppendChild(cmd);
            }
            _recipe.GetElementsByTagName("recipe")[0].AppendChild(cooking);
        }
    }
}
